package applets

import (
	"fmt"
	"time"

	"commonUtils/utils"
)

type WXData struct {
	appid       string
	appsecret   string
	token       string
	tokenTime   time.Time
	tokenExpire int
	http        *utils.HTTPClient
}

var instWXData *WXData

func WXDataInst() *WXData {
	if instWXData == nil {
		instWXData = &WXData{
			http: utils.NewHTTPClient(),
		}
	}
	return instWXData
}

func (a *WXData) AppID(id string) {
	a.appid = id
}
func (a *WXData) AppSecret(sec string) {
	a.appsecret = sec
}

// Token获取
type TokenRet struct {
	AccessToken string `json:"access_token" validate:"required"`
	ExpireSec   int    `json:"expires_in" validate:"required"`
}

func (a *WXData) isTokenExpired() bool {
	if a.token == "" {
		return true
	}
	return time.Now().After(a.tokenTime.Add(time.Duration(a.tokenExpire) * time.Second))
}

func (a *WXData) GetToken() (string, error) {

	if a.isTokenExpired() {
		return a.token, nil
	}

	return a.refreshToken()
}

func (a *WXData) refreshToken() (string, error) {

	u := "https://api.weixin.qq.com/cgi-bin/token"

	query := map[string]string{
		"grant_type": "client_credential",
		"appid":      a.appid,
		"secret":     a.appsecret,
	}

	u += "?" + utils.MapToUrlencode(query)

	utils.Debug("code 2 session url : %s", u)
	ret, _, _, err := a.http.Get(u, nil)
	if err != nil {
		return "", err
	}

	var tokenRet *TokenRet

	err = utils.JsonToStruct(ret, &tokenRet)
	if err != nil {
		return "", err
	}

	validate := utils.GetValidate()

	if err := validate.Struct(tokenRet); err != nil {
		return "", err
	}

	a.token = tokenRet.AccessToken
	a.tokenExpire = tokenRet.ExpireSec
	a.tokenTime = time.Now()

	return a.token, nil
}

// session登录
type Code2SessionRet struct {
	SessionKey string `json:"session_key"`
	OpenID     string `json:"openid"`
	UnionID    string `json:"unionid"`
	ErrCode    int32  `json:"errcode"`
	Errmsg     string `json:"errmsg"`
}

func (a *WXData) Code2Session(code string) (*Code2SessionRet, error) {
	u := "https://api.weixin.qq.com/sns/jscode2session"

	query := map[string]string{
		"appid":      a.appid,
		"secret":     a.appsecret,
		"js_code":    code,
		"grant_type": "authorization_code",
	}

	u += "?" + utils.MapToUrlencode(query)

	utils.Debug("code 2 session url : %s", u)
	ret, _, _, err := a.http.Get(u, nil)
	if err != nil {
		return nil, err
	}

	var sessionRet *Code2SessionRet

	err = utils.JsonToStruct(ret, &sessionRet)
	if err != nil {
		return nil, err
	}

	return sessionRet, nil
}

// 获取手机号 接口只开放给企业用户，个人开发者不可用
// https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html
func (a *WXData) GetPhoneNumber(code string) (string, error) {
	token, err := a.GetToken()
	if err != nil {
		return "", err
	}
	u := "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + token

	ret, _, _, err := a.http.Post(u, map[string]interface{}{
		"code": code,
	}, nil)
	if err != nil {
		return "", err
	}

	var data map[string]interface{}
	data, err = utils.JsonToMap(ret)
	if err != nil {
		return "", err
	}
	info, ok := data["phone_info"].(map[string]interface{})
	if !ok {
		return "", fmt.Errorf("手机信息获取错误")
	}
	phone, ok := info["phoneNumber"].(string)

	if !ok {
		return "", fmt.Errorf("手机号获取错误")
	}

	return phone, nil
}
